﻿Namespace VMObjects
    <Serializable()>
    Public Class PowerCollection(Of T)
        Inherits System.Collections.ObjectModel.Collection(Of T)
        Implements System.ICloneable
        Implements System.IDisposable

        Public Event CountChanging(ByVal sender As VMGenLibrary.VMObjects.PowerCollection(Of T), ByVal e As VMGenLibrary.Structures.PowercollectionEventArgs)
        Public Event CountChanged(ByVal sender As VMGenLibrary.VMObjects.PowerCollection(Of T), ByVal e As VMGenLibrary.Structures.PowercollectionEventArgs)
        Public Event NowEmpty(ByVal sender As VMGenLibrary.VMObjects.PowerCollection(Of T))
        Public Event QueryEmpty(ByVal sender As VMGenLibrary.VMObjects.PowerCollection(Of T))
        Public Event QueryRemove(ByVal sender As VMGenLibrary.VMObjects.PowerCollection(Of T), ByVal IndexToRemove As Integer)
        Public Event ItemsExchanging(ByVal sender As VMGenLibrary.VMObjects.PowerCollection(Of T), ByVal e As VMGenLibrary.Structures.PowercollectionEventArgs)
        Public Event ItemsExchanged(ByVal sender As VMGenLibrary.VMObjects.PowerCollection(Of T), ByVal e As VMGenLibrary.Structures.PowercollectionEventArgs)
        Public Event ItemsMoving(ByVal sender As VMGenLibrary.VMObjects.PowerCollection(Of T), ByVal e As VMGenLibrary.Structures.PowercollectionEventArgs)

        Private IsMovingOperation As Boolean
        Private IsExchangeOperation As Boolean
        Private LastAddedValue As T = Nothing

#Region "PROPERTIES"
        Public Overloads ReadOnly Property Count
            Get
                Return MyBase.Count
            End Get
        End Property
        Public ReadOnly Property LastAdded As T
            Get
                Return LastAddedValue
            End Get
        End Property
#End Region
#Region "METHODS"
        Protected Overrides Sub InsertItem(ByVal Index As Integer, ByVal Item As T)
            Dim e As New VMGenLibrary.Structures.PowercollectionEventArgs
            With e
                .Action = VMGenLibrary.Structures.CountChangedAction.Added
                .ObjectMoved = Item
                .OldCount = MyBase.Count
                .NewCount = MyBase.Count + 1
                .GoingToBeEmpty = False
            End With
            If IsMovingOperation = False And IsExchangeOperation = False Then RaiseEvent CountChanging(Me, e)
            MyBase.InsertItem(Index, Item)
            LastAddedValue = Item
            If IsMovingOperation = False And IsExchangeOperation = False Then RaiseEvent CountChanged(Me, e)
        End Sub
        Protected Overrides Sub RemoveItem(ByVal Index As Integer)
            Dim e As New VMGenLibrary.Structures.PowerCollectionEventArgs
            With e
                .Action = VMGenLibrary.Structures.CountChangedAction.Removed
                .ObjectMoved = Item(Index)
                .OldCount = MyBase.Count
                .NewCount = MyBase.Count - 1
                If .NewCount = 0 Then .GoingToBeEmpty = True Else .GoingToBeEmpty = False
            End With
            If IsMovingOperation = False And IsExchangeOperation = False Then RaiseEvent CountChanging(Me, e)
            If IsMovingOperation = False And IsExchangeOperation = False Then RaiseEvent QueryRemove(Me, Index)
            If Me.Count = 1 Then
                RaiseEvent QueryEmpty(Me)
            End If
            MyBase.RemoveItem(Index)
            If IsMovingOperation = False And IsExchangeOperation = False Then RaiseEvent CountChanged(Me, e)
            If Me.Count = 0 Then
                RaiseEvent NowEmpty(Me)
            End If
        End Sub
        Public Sub ExchangeIndex(ByVal Index1 As Integer, ByVal Index2 As Integer)
            RaiseEvent ItemsExchanging(Me, New PowerCollectionEventArgs)
            IsExchangeOperation = True
            Dim Buffer As Object
            If Index1 > MyBase.Count Or Index2 > MyBase.Count Or Index1 < 0 Or Index2 < 0 Then
                Exit Sub
            End If
            Buffer = MyBase.Item(Index1)
            SetItem(Index1, MyBase.Item(Index2))
            SetItem(Index2, Buffer)
            RaiseEvent ItemsExchanged(Me, New PowerCollectionEventArgs)
            IsExchangeOperation = False
        End Sub
        Public Function Exist(ByVal Item As T) As Boolean
            If IndexOf(Item) = -1 Then
                Return False
            Else
                Return (True)
            End If
        End Function
        Public Sub MoveToIndex(ByVal IndexSource As Integer, ByVal IndexDestination As Integer)
            RaiseEvent ItemsMoving(Me, New PowerCollectionEventArgs)
            IsMovingOperation = True
            IndexSource = Math.Max(IndexSource, 0)
            IndexSource = Math.Min(IndexSource, Items.IndexOf(Items.Last))
            IndexDestination = Math.Max(IndexDestination, 0)
            IndexDestination = Math.Min(IndexDestination, Items.IndexOf(Items.Last))
            Dim It As T = Item(IndexSource)
            Items.RemoveAt(IndexSource)
            If IndexDestination = Items.IndexOf(Items.Last) + 1 Then
                Add(It)
            Else
                InsertItem(IndexDestination, It)
            End If
            IsMovingOperation = False
        End Sub
        Public Function Clone() As Object Implements ICloneable.Clone
            Dim NewList As New PowerCollection(Of T)
            If Me.Count > 0 Then
                For Each El As T In Me
                    NewList.Add(CType(El, ICloneable).Clone)
                Next
            End If
            Return NewList
        End Function
#End Region

#Region "IDisposable Support"
        Private disposedValue As Boolean ' Per rilevare chiamate ridondanti

        ' IDisposable
        Protected Overridable Sub Dispose(ByVal disposing As Boolean)
            If Not Me.disposedValue Then
                If disposing Then
                    ' TODO: eliminare stato gestito (oggetti gestiti).
                End If

                ' TODO: liberare risorse non gestite (oggetti non gestiti) ed eseguire l'override del seguente Finalize().
                ' TODO: impostare campi di grandi dimensioni su null.
            End If
            Me.disposedValue = True
        End Sub

        ' TODO: eseguire l'override di Finalize() solo se Dispose(ByVal disposing As Boolean) dispone del codice per liberare risorse non gestite.
        'Protected Overrides Sub Finalize()
        '    ' Non modificare questo codice. Inserire il codice di pulizia in Dispose(ByVal disposing As Boolean).
        '    Dispose(False)
        '    MyBase.Finalize()
        'End Sub

        ' Questo codice è aggiunto da Visual Basic per implementare in modo corretto il modello Disposable.
        Public Sub Dispose() Implements IDisposable.Dispose
            ' Non modificare questo codice. Inserire il codice di pulizia in Dispose(ByVal disposing As Boolean).
            Dispose(True)
            GC.SuppressFinalize(Me)
        End Sub
#End Region

    End Class
End Namespace
